﻿/*
 * TagBase
 * 
 * initial implementation : 5.12.2008
 *
 * Copyright (c) Adam Sida, asida@centrum.cz.
 * All rights reserved.
 * 
 * for license see Petra.Gis.License.txt
 */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;


namespace Petra.Gis.ImagingServices.Tiff
{

  ///<summary>
  /// represents the data stored in a TIFF <class>Tag</class> (a single image file directory entry).
  /// That includes the following items:
  /// identification number, 254 or higher; see the many TAG_xyz constants in
  /// {@link TIFFConstants} for a list of allowed values
  /// type; the allowed types include integer and floating point numbers, Strings etc.;
  /// see the TAG_TYPE_xyz constants in {@link TIFFConstants}
  /// count; the number of values of the given type that are stored in this tag;
  /// 1 or higher
  /// offset; if count is 1 and the type fits into four bytes, this is the complete
  ///  value of this tag; otherwise, it is an offset into the file to the position
  ///  that will hold the value(s)
  ///
  ///See the TIFF specification manual linked in the description of {@link TIFFCodec}
  ///for more details.
  ///</summary>
public abstract class TagBase
{
	
  protected int _tagNumber;
	protected int _count;
	protected int _offset;
  //protected object _tagData;
  //private ImageFileDirectory _parentIfd;


  /// <summary>
  /// xaml constr.
  /// </summary>
  protected TagBase(){}




  ///<summary>
  /// Creates a new tag with the given ID, type, number of objects / primitives stored in it
  /// and offset value.
  ///</summary>
  protected TagBase(int id, TagDataType type, int count, int offset)
	{
    _tagNumber = id;
		_tagId = (TagType)id;
		_type = type;
		_count = count;
		if (count < 1)
		{
			throw new ArgumentException("Tiff tag count value must " +
				"not be smaller than 1: " + count);
		}
		_offset = offset;
    //_tagData = null;
    //_parentIfd = ifd;
	}




  /// <summary>
  /// Returns the number of items stored in this tag.
  /// </summary>
	public int Count
	{
    get { return _count; }
	}


  

  
  //public int getElementAsInt(int index)
  //{
  //  Object element = getObject(index);

  //  if (element == null)
  //  {
  //    throw new ArgumentException("Tag does not contain a list of values.");
  //  }

  //  if (element.GetType() == typeof(short))
  //  {
  //    return (short)element;
  //  }
  //  if (element.GetType() == typeof(ushort))
  //  {
  //    return (ushort)element;
  //  }

  //  if (element.GetType() == typeof(int))
  //  {
  //    return (int)element;
  //  }

  //  if (element.GetType() == typeof(Byte))
  //  {
  //    return (Byte)element;
  //  }

  //  throw new ArgumentException("Element #" + index + " is not an integer value.");
  //}





  protected TagType _tagId;


  /// <summary>
  /// Returns the ID of this tag, which may be one of the TAG_xyz constants.
  /// </summary>
  public TagType Id
	{
		get{return _tagId;}
	}





  ///// <summary>
  ///// Returns an object from this tag's Vector of items,
  ///// <code>null</code> if no such Vector exists.
  ///// </summary>
  ///// <param name="index"></param>
  ///// <returns></returns>
  //public Object getObject(int index)
  //{
  //  if (_tagData == null)
  //  {
  //    return null;
  //  }
  //  else
  //  {
  //    return _tagData[index];
  //  }
  //}




	/**
	 * Returns the offset value stored in this tag.
	 */
	public int Offset
	{
		get{return _offset;}
	}





  ///**
  // * If this tag has a Vector of items and if the first item
  // * is a String, that String is returned, <code>null</code>
  // * otherwise.
  // */
  //public String getString()
  //{
  //  if (_tagData != null && _tagData.Count > 0)
  //  {
  //    object o = _tagData[0];
  //    if (o != null && o.GetType() == typeof(String))
  //    {
  //      return (String)o;
  //    }
  //  }
  //  return null;
  //}



  
  protected TagDataType _type;


  /// <summary>
  ///  Returns the type of this tag's content as a TAG_TYPE_xyz constant.
  /// </summary>
 	public TagDataType Type
	{
    get { return _type; }
	}







  protected abstract IList tifTagData {get; set;}

  /// <summary>
  /// Returns/sets the List of items stored in this tag.
  /// If this tag encapsulates more than one item or a single
  /// item that does not fit into four bytes, this Vector
  /// will store all elements in it.
  /// the same value as getCount().
  /// </summary>
  public IList TagData
  {
    get { return tifTagData; }
    set { tifTagData = value; } 
  }




  /// <summary>
  /// Returns if the value(s) stored in this tag are of type byte, short or
	/// long.
	/// Note that byte and short have the same meaning as in Java/C# (one and two bytes 
	/// large) while long is a 32-bit-value, just like <code>int</code> in Java/C#.
  /// </summary>
  /// <returns>true if this tag's contains integer values &lt;= 32 bits</returns>
	public bool isInt()
	{
    return (_type == TagDataType.BYTE || _type == TagDataType.SHORT || _type == TagDataType.LONG);
	}




  public override string ToString()
  {
    return _tagId.ToString();
  }




  public static TagBase Create(TiffReader tiffReader)
  {

    TagType t;

    int tagNumber = (int)tiffReader.ReadUInt16();
    try { t = (TagType)tagNumber; }
    catch { t = TagType.UNKNOWN; }

    // revert stream position
    tiffReader.BaseStream.Seek(-2, SeekOrigin.Current);

    switch (t)
    { 
      case TagType.TILEOFFSETS:
      case TagType.STRIPOFFSETS:
      case TagType.STRIPBYTECOUNTS:
      case TagType.TILEBYTECOUNTS:
        return new UIntArrayTag(tiffReader);
      case TagType.COLORMAP:
        return new UShortArrayTag(tiffReader);
      default:
        return new Tag(tiffReader);
    }

    //TagDataType datatype = (TagDataType)tiffReader.ReadInt16();
    //int count = tiffReader.ReadInt32();
    //int offset = tiffReader.ReadInt32();



  }



  protected bool dataOustideIfd(TagDataType type, int count)
  {
    if ((count == 1 && (type == TagDataType.BYTE ||
                       type == TagDataType.ASCII ||
                       type == TagDataType.SHORT ||
                       type == TagDataType.LONG ||
                       type == TagDataType.SBYTE ||
                       type == TagDataType.SSHORT ||
                       type == TagDataType.SLONG)) ||
        (count <= 4 && (type == TagDataType.BYTE ||
                       type == TagDataType.ASCII ||
                       type == TagDataType.SBYTE)) ||
        (count <= 2 && (type == TagDataType.SHORT ||
                        type == TagDataType.SSHORT))

        )
    {
      // value in offset is data
      // must read data direcly no pointer to file
      return false;
    }
    else
    {
      // value is offset because data are not big enough
      // to fit into tag offset property
      return true;
    }

  }


 }
}